/**
 * 
 * Copyright 2009 Marco Speranza <marco.speranza79@gmail.com>
 *    
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *   
 * http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.commons.util.conversion;

/**
 * Procedura di utilita' per convertire valori esadecimali in decimali, e
 * viceversa.
 * 
 * @author Marco Speranza
 */

public final class HexConv {
    /**
     * Converte in un intero il numero esadecimale contenuto nel byte in input.
     * 
     * @param b
     *            il byte da convertire
     * @return il valore decimale calcolato
     */
    public static int hexInt(byte b) {
	int value = (int) b;
	return (value < 0) ? value + 256 : value;
    } // end hexInt()

    /**
     * Converte in un decimale il numero esadecimale contenuto nel buffer in
     * input (su 2 byte), assumendo il Big Endian order: MSB, LSB.
     * 
     * @param buffer
     *            il buffer contenente la word (MSB, LSB)
     * @param offset
     *            la posizione in cui inizia la word
     * @return il valore decimale corrispondente
     */
    public static int hexInt(byte[] buffer, int offset) {
	return HexConv.hexInt(buffer[offset], buffer[offset + 1]);
    } // end hexInt()

    /**
     * Converte in un decimale il numero esadecimale in input.
     * 
     * @param msb
     *            il byte pi� significativo
     * @param lsb
     *            il byte meno significativo
     * @return il valore decimale corrispondente
     */
    public static int hexInt(byte msb, byte lsb) {
	int iMsb = HexConv.hexInt(msb);
	int iLsb = HexConv.hexInt(lsb);
	return (iMsb * 256 + iLsb);
    } // end hexInt()

    /**
     * Converte in un float il numero esadecimale contenuto nel buffer in input
     * (su 4 byte). Assume il seguente ordine: LsbL, Lsb, Msb, MsbM
     * 
     * @param buffer
     *            il buffer contenente la word (LL, L, M, MM)
     * @param offset
     *            la posizione da cui inizia la word
     * @return il valore float calcolato.
     */
    public static float bufferToFloat(byte[] buffer, int offset) {
	int v0 = HexConv.hexInt(buffer[offset]);
	int v1 = HexConv.hexInt(buffer[offset + 1]);
	int v2 = HexConv.hexInt(buffer[offset + 2]);
	int v3 = HexConv.hexInt(buffer[offset + 3]);

	// 16777216 = 65536 * 256
	int value = v3 * 16777216;
	value += (v2 * 65536);
	value += (v1 * 256);
	value += v0;

	float risultato = Float.intBitsToFloat(value);
	return risultato;
    } // end bufferToFloat()

    /**
     * Restituisce una stringa che rappresenta un numero intero in formato
     * esadecimale espresso su tante cifre quanto specificato, quindi con
     * eventuali 0 (zero) davanti.
     * 
     * @param value
     *            il numero intero da rappresentare in esadecimale
     * @param digit
     *            le cifre con cui costruire la stringa
     * @return la stringa formattata.
     */
    private static String hexString(int value, int digit) {
	String s = "0000" + Integer.toHexString(value);
	return s.substring(s.length() - digit);
    } // end hexString()

    /**
     * Converte in una stringa di due cifre esadecimali il valore in input.
     * 
     * @param value
     *            il byte da convertire
     * @return la stringa formattata.
     */
    public static String hexString(byte value) {
	return hexString((int) value, 2);
    } // end hexString()

    /**
     * Rappresenta un buffer di bytes in una stringa di numeri esadecimali; ogni
     * 16 valori ritorna a capo per una nuova linea.
     * 
     * @param data
     *            il buffer da convertire in stringa
     * @param ofst
     *            la posizione da cui cominciare la conversione
     * @param len
     *            la dimensione del buffer
     * @return la stringa formattata.
     */
    public static String dumpBufferToString(byte[] data, int ofst, int len) {
	String s = "";
	int pos = 0;

	for (int i = 0; i < len; i++) {
	    s += HexConv.hexString(data[ofst + i]) + " ";
	    pos++;
	    if (pos == 16) {
		s = s + "\r\n";
		pos = 0;
	    }
	}
	return s;
    } // end dumpBufferToString()

    /**
     * Rappresenta un buffer di bytes in una stringa di numeri esadecimali.
     * 
     * @param data
     *            il buffer da convertire in stringa
     * @param ofst
     *            la posizione da cui cominciare la conversione
     * @param len
     *            la dimensione del buffer
     * @return la stringa formattata.
     */
    public static String bufferToString(byte[] data, int ofst, int len) {
	StringBuffer sb = new StringBuffer();

	for (int i = 0; i < len; i++) {
	    sb.append(HexConv.hexString(data[ofst + i]));
	    sb.append(" ");
	}
	return sb.toString().trim();
    } // end bufferToString()
}
